﻿#include "MallManager.h"
#include "CenterService.h"
#include "Common/GlobalDefine.h"
#include "Cache/OfflineCharacterDataMgr.h"
#include "Active/ActiveCharacter.h"
#include "Active/ActiveCharacterMgr.h"
#include "Script/ScriptMgr_CS.h"
#include "Union/UnionMgr.h"
#include "Common/LogDefine.h"
#include "MailCenter/MailManager.h"

MallManager::MallManager() :m_bFinishLoad(false), m_bMallNeedSave(false)
{
	_mallItemPool = new ObjectPool < MallItem >;
	m_mapMallItem.clear();

	m_mapMallCfg.clear();
	m_mapGlobalMallGoods.clear();
	m_mapBuyItem.clear();
	m_mapCampMallGoods.clear();
	m_mapAllGuildMall.clear();
	m_mapGuildMallGoods.clear();
	m_mapAranaMallGoods.clear();
	m_mapRunMallGoods.clear();
	_m_mapRunMallGoods.clear();
	m_unionLevMallMap.clear();
}

MallManager::~MallManager()
{
	MallItemIter iter = m_mapMallItem.begin();
	while (iter != m_mapMallItem.end())
	{
		if (nullptr != iter->second)
		{
			_mallItemPool->FreeObj(iter->second);
			iter->second = nullptr;
		}
		m_mapMallItem.erase(iter++);
	}

	MMO_DELETE(_mallItemPool);
}

bool MallManager::Init()
{
	IMessageDispatch *pMessageDispatch = g_GetCenterService()->GetServiceMessageDispatch();
	if (nullptr == pMessageDispatch)
	{
		MMOLOG_FMT_ERROR("[center] MallManager::Init....nullptr == pMessageDispatch ");
		return false;
	}
	pMessageDispatch->registerDBProxyHandler(EMODULE_ID_MALL, this);
	pMessageDispatch->registerClientHandler(EMODULE_ID_MALL, this);
	pMessageDispatch->registerServerHandler(EMODULE_ID_MALL, this);

	g_GetActiveCharacterMgr()->AddCharacterObserver(this);

	g_GetTimerAxis()->SetTimer(ETimer_ID_Load_Mall, 2 * 1000, this);
	g_GetTimerAxis()->SetTimer(ETimer_ID_Save_Mall, 60 * 1000, this);
	g_GetTimerAxis()->SetTimer(ETimer_ID_Refrsh_Mall, 1 * 1000, this);
	//g_GetTimerAxis()->SetTimer(ETimer_ID_Run_Mall, 60 * 10 * 1000, this);

	//LoadConfig();
	InitMallConfig();
	RefreshRunGoods();
	return true;
}

bool MallManager::UnInit()
{
	IMessageDispatch *pMessageDispatch = g_GetCenterService()->GetServiceMessageDispatch();
	if (nullptr != pMessageDispatch)
	{
		pMessageDispatch->unregisterDBProxyHandler(EMODULE_ID_MALL);
		pMessageDispatch->unregisterClientHandler(EMODULE_ID_MALL);
		pMessageDispatch->unregisterServerHandler(EMODULE_ID_MALL);
	}

	g_GetTimerAxis()->KillAllTimer(this);
	g_GetTimerAxis()->KillAllFixTimer(this);

	g_GetActiveCharacterMgr()->RemoveCharacterObserver(this);

	m_bFinishLoad = false;
	m_mapMallCfg.clear();
	m_mapGlobalMallGoods.clear();
	m_mapBuyItem.clear();
	m_mapCampMallGoods.clear();
	m_mapAllGuildMall.clear();
	m_mapGuildMallGoods.clear();
	m_mapAranaMallGoods.clear();
	m_mapRunMallGoods.clear();
	_m_mapRunMallGoods.clear();
	m_unionLevMallMap.clear();

	return true;
}

void MallManager::SaveDB(bool close)
{
	SaveMallDataReq(close);
	SaveCharacterMallDataReq(close);
}

/*
void MallManager::LoadConfig()
{
	LuaScript *pScript = g_GetCSScriptMgr()->GetScript();
	MMOLOG_ASSERT(pScript != nullptr);

	bool retCode = false;
	LuaRef refRet(pScript->GetState());

	retCode = pScript->CallTableFuncRet("Mall", "LoadAllMallConfig", refRet);
	MMO_ASSERT(retCode && refRet.isTable());

	int32_t len = refRet.length();
	if (len <= 0)	return;

	m_mapMallCfg.clear();

	for (int32_t i = 1; i <= len; i++)
	{
		luabridge::LuaRef refMall = refRet[i];
		if (!refMall.isTable())
		{
			continue;
		}

		MallCfgInfo info;
		uint32_t mallid = refMall["id"].cast<uint32_t>();

		info.itemID = refMall["itemID"].isNil() ? 0 : refMall["itemID"].cast<uint32_t>();
		info.mallType = refMall["mallType"].isNil() ? 0 : refMall["mallType"].cast<uint32_t>();
		info.priority = refMall["priority"].isNil() ? 0 : refMall["priority"].cast<uint32_t>();
		info.moneyType = refMall["moneyType"].isNil() ? 0 : refMall["moneyType"].cast<uint32_t>();
		info.price = refMall["price"].isNil() ? 0 : refMall["price"].cast<uint32_t>();
		info.discount = refMall["discount"].isNil() ? 0 : refMall["discount"].cast<uint32_t>();
		info.buyAmount = refMall["buyAmount"].isNil() ? 0 : refMall["buyAmount"].cast<uint32_t>();
		info.refreshTime = refMall["refreshTime"].isNil() ? 0 : refMall["refreshTime"].cast<uint32_t>();
		info.goodsAmount = refMall["goodsAmount"].isNil() ? 0 : refMall["goodsAmount"].cast<uint32_t>();
		info.goodsRefreshTime = refMall["goodsRefreshTime"].isNil() ? 0 : refMall["goodsRefreshTime"].cast<uint32_t>();
		info.vipLimit = refMall["vipLimit"].isNil() ? 0 : refMall["vipLimit"].cast<uint32_t>();
		info.levelLimit = refMall["levelLimit"].isNil() ? 0 : refMall["levelLimit"].cast<uint32_t>();
		info.openTime = refMall["openTime"].isNil() ? 0 : refMall["openTime"].cast<uint32_t>();
		info.openCoolTime = refMall["openCoolTime"].isNil() ? 0 : refMall["openCoolTime"].cast<uint32_t>();
		info.isClose = refMall["isClose"].isNil() ? 0 : refMall["isClose"].cast<uint32_t>();
		info.sellWaitingTime = refMall["sellWaitingTime"].isNil() ? 0 : refMall["sellWaitingTime"].cast<uint32_t>();
		m_mapMallCfg[mallid] = info;
	}
}*/

void MallManager::InitMallConfig()
{
	const MallMallCfgMap *allMallCfg = g_GetMallMallCfgTable()->GetMallMallCfgMap();
	if (nullptr == allMallCfg)		return;

	for (MallMallCfgMap::const_iterator it = allMallCfg->begin(); it != allMallCfg->end(); it++)
	{
		const MallMallCfgInfo &mCfg = it->second;
		const MallMalltypeCfgInfo *pMallTypeCfg = g_GetMallMalltypeCfgTable()->GetMallMalltypeCfgInfo(mCfg.mallType);
		if (nullptr == pMallTypeCfg)
		{
			MMOLOG_FMT_ERROR("[center] MallManager::InitMallConfig pMallTypeCfg=nullptr.......failed...mallType:%d", mCfg.mallType);
			continue;;
		}

		if (Mall_Sub_Type_Guild == pMallTypeCfg->logicType)
		{
			InitGuildGoods(mCfg);
			continue;
		}
		if (Mall_Sub_Type_Camp == pMallTypeCfg->logicType)
		{
			InitCampGoods(mCfg);
			continue;
		}
		if (Mall_Sub_Type_Arena == pMallTypeCfg->logicType)
		{
			InitAranaGoods(mCfg);
			continue;
		}
		if (Mall_Sub_Type_Run == pMallTypeCfg->logicType)
		{
			InitRunGoods(mCfg);
			continue;
		}
		if (mCfg.buyAmount > 0)		//限购商品
		{
			MallGoods goods;
			goods.mallid = mCfg.id;
			goods.buyAmount = mCfg.buyAmount;
			goods.buyTime = mCfg.refreshTime;
			goods.openTime = mCfg.openTime;
			InitGoods(goods);
			m_mapBuyItem.insert(make_pair(mCfg.id, goods));
		}
		//if (mCfg.goodsAmount > 0 || (mCfg.goodsAmount == 0 && mCfg.buyAmount == 0 && mCfg.openTime > 0))	//限销商品
		if (mCfg.goodsAmount > 0 || mCfg.openTime > 0)	//限销商品、有开放时限商品
		{
			MallGoods goods;
			goods.mallid = mCfg.id;
			goods.goodsAmount = mCfg.goodsAmount;
			goods.goodsTime = mCfg.goodsRefreshTime;
			goods.openTime = mCfg.openTime;
			InitGoods(goods);
			goods.startTick = Time::Tick();
			goods.startTick_s = goods.goodsAmount > 0 ? goods.goodsTime : (goods.openTime > 0 ? goods.openTime : 0);
			//goods.startTick_s = mCfg.goodsRefreshTime;
			m_mapGlobalMallGoods.insert(make_pair(mCfg.id, goods));
		}
	}

	MALL_GOODS_MAP guildmap;
	for (int32_t shopLev = 1; shopLev <= 5; ++shopLev)
	{
		guildmap.clear();
		RefreshGuildGoods(guildmap, shopLev);
		m_unionLevMallMap[shopLev] = guildmap;
	}
}

void MallManager::InitGoods(MallGoods &goods)
{
	const MallMallCfgInfo *pMallcfg = g_GetMallMallCfgTable()->GetMallMallCfgInfo(goods.mallid);
	if (nullptr == pMallcfg)
	{
		LogErrFmtPrint("[center] MallManager::InitGoods...nullptr == pMallcfg  mallid:%u ", goods.mallid);
		return;
	}
	goods.Init(pMallcfg, pMallcfg->buyAmount, pMallcfg->goodsAmount, pMallcfg->goodsRefreshTime, pMallcfg->refreshTime, pMallcfg->openTime, pMallcfg->openCoolTime, pMallcfg->refreshWeight);
}

inline void merge(GUILD_RAND_MAP &map, MallGoods &goods, const MallMallCfgInfo &mCfg)
{
	static uint32_t guild_level_max = 5;
	for (uint32_t i = 1; i <= guild_level_max; i++)
	{
		if (i < (uint32_t)mCfg.sellLevel)
			continue;

		GUILD_RAND_MAP::iterator iter = map.find(i);
		if (iter != map.end())
		{
			MallCfg_RandInfo &info = iter->second;
			info.vec.push_back(goods);
			info.totalRand += mCfg.refreshWeight;
		}
		else
		{
			MallCfg_RandInfo info;
			info.vec.push_back(goods);
			info.totalRand += mCfg.refreshWeight;
			map.insert(make_pair(i, info));
		}
	}
}

void MallManager::InitCampGoods(const MallMallCfgInfo &mCfg)
{
	if (mCfg.escheatageId <= 0)
	{
		LogErrFmtPrint("[center] MallManager::InitCampGoods..mCfg.escheatageId <= 0  mallid:%u ", mCfg.id);
	}

	MallGoods goods;
	goods.mallid = mCfg.id;
	goods.buyAmount = mCfg.buyAmount;
	InitGoods(goods);

	CAMP_GOODS_MAP::iterator iter = m_mapCampMallGoods.find(mCfg.escheatageId);
	if (iter != m_mapCampMallGoods.end())
	{
		MallCfg_RandInfo &info = iter->second;
		info.vec.push_back(goods);
		info.totalRand += mCfg.refreshWeight;
	}
	else
	{
		MallCfg_RandInfo info;
		info.vec.push_back(goods);
		info.totalRand += mCfg.refreshWeight;
		m_mapCampMallGoods.insert(make_pair(mCfg.escheatageId, info));
	}
}

void MallManager::InitGuildGoods(const MallMallCfgInfo &mCfg)
{
	if (mCfg.escheatageId <= 0)
	{
		LogErrFmtPrint("[center] MallManager::InitGuildGoods..mCfg.escheatageId <= 0  mallid:%u ", mCfg.id);
	}

	MallGoods goods;
	goods.mallid = mCfg.id;
	InitGoods(goods);
	goods.buyAmount = goods.cBuyAmount;

	GUILD_GOODS_MAP::iterator iter = m_mapGuildMallGoods.find(mCfg.escheatageId);
	if (iter != m_mapGuildMallGoods.end())
	{
		GUILD_RAND_MAP &map = iter->second;
		merge(map, goods, mCfg);
	}
	else
	{
		GUILD_RAND_MAP map;
		merge(map, goods, mCfg);
		m_mapGuildMallGoods.insert(make_pair(mCfg.escheatageId, map));
	}
}

void MallManager::InitAranaGoods(const MallMallCfgInfo &mCfg)
{
	MallGoods goods;
	goods.mallid = mCfg.id;
	goods.buyAmount = mCfg.buyAmount;
	InitGoods(goods);
	m_mapAranaMallGoods.insert(make_pair(mCfg.id, goods));
}

inline void merge_run(RUN_RAND_MAP &map, MallGoods &goods, const MallMallCfgInfo &mCfg)
{
	RUN_RAND_MAP::iterator iter = map.find(mCfg.escheatageId);
	if (iter != map.end())
	{
		MallCfg_RandInfo &info = iter->second;
		info.vec.push_back(goods);
		info.totalRand += mCfg.refreshWeight;
	}
	else
	{
		MallCfg_RandInfo info;
		info.vec.push_back(goods);
		info.totalRand += mCfg.refreshWeight;
		map.insert(make_pair(mCfg.escheatageId, info));
	}
}

void MallManager::InitRunGoods(const MallMallCfgInfo &mCfg)
{
	//方案1:每个货架买和卖随机刷3-5个
	MallGoods goods;
	goods.mallid = mCfg.id;
	goods.goodsAmount = mCfg.goodsAmount;
	//goods.buyAmount = mCfg.buyAmount;
	InitGoods(goods);
	m_mapRunMallGoods.insert(make_pair(mCfg.id, goods));

	//方案2:根据商城配置的escheatageId、refreshWeight刷  当前使用方案2
	if (mCfg.escheatageId <= 0)
	{
		LogErrFmtPrint("[center] MallManager::InitRunGoods..mCfg.escheatageId <= 0  mallid:%u ", mCfg.id);
		return;
	}
	RUN_GOODS_MAP::iterator iter = _m_mapRunMallGoods.find(mCfg.mallType);
	if (iter != _m_mapRunMallGoods.end())
	{
		RUN_RAND_MAP &map = iter->second;
		merge_run(map, goods, mCfg);
	}
	else
	{
		RUN_RAND_MAP map;
		merge_run(map, goods, mCfg);
		_m_mapRunMallGoods.insert(make_pair(mCfg.mallType, map));
	}
}

MALL_GOODS_MAP MallManager::RefreshCampGoods()
{
	MALL_GOODS_MAP cMap;
	for (CAMP_GOODS_MAP::iterator iter = m_mapCampMallGoods.begin(); iter != m_mapCampMallGoods.end(); iter++)
	{
		MallCfg_RandInfo &info = iter->second;
		uint32_t randint = Random(info.totalRand + 1);
		uint32_t temp = 0;
		for (CAMP_GOODS_VEC::iterator it = info.vec.begin(); it != info.vec.end(); ++it)
		{
			temp += (*it).cRefreshWeight;
			if (randint <= temp)
			{
				cMap.insert(make_pair((*it).mallid, *it));
				break;
			}
		}
	}
	return cMap;
}

MALL_GOODS_MAP MallManager::RefreshArenaGoods()
{
	//MALL_GOODS_MAP cMap;
	//TODO:竞技场刷新规则
	return m_mapAranaMallGoods;
}

MALL_GOODS_MAP MallManager::RefreshUnionGoods(uint32_t shopLevel/*公会商铺等级*/)
{
	MALL_GOODS_MAP mMap;
	UnionLevMallIter iter = m_unionLevMallMap.find(shopLevel);
	if (iter != m_unionLevMallMap.end())
		return iter->second;
	return mMap;
}

void MallManager::RefreshRunGoods()
{
	//m_mapRunGoods.clear();
	m_runMallInfo.preRunMap.clear();
	m_runMallInfo.preRunMap = m_runMallInfo.runMap;
	m_runMallInfo.runMap.clear();
	/*std::map<uint32_t, std::vector<uint32_t> > rMap;
	for (MALL_GOODS_MAP::iterator iter = m_mapRunMallGoods.begin(); iter != m_mapRunMallGoods.end(); iter++)
	{
	std::map<uint32_t, std::vector<uint32_t> >::iterator it = rMap.find(iter->second.mPmallcfg->mallType);
	if (it == rMap.end())
	{
	std::vector<uint32_t> cVec;
	cVec.push_back(iter->first);
	rMap.insert(std::make_pair(iter->second.mPmallcfg->mallType, cVec));
	}
	else
	{
	std::vector<uint32_t> &cVec = it->second;
	cVec.push_back(iter->first);
	}
	}

	std::set<uint32_t> iset;
	for (std::map<uint32_t, std::vector<uint32_t> >::iterator iter = rMap.begin(); iter != rMap.end(); iter++)
	{
	DoRun(iset, iter->second);
	}

	for (std::set<uint32_t>::iterator iter = iset.begin(); iter != iset.end(); iter++)
	{
	MallGoods &goods = m_mapRunMallGoods[*iter];
	if (goods.mPmallcfg->price > 0)
	{
	goods.buyPrice = Random(goods.mPmallcfg->price - goods.mPmallcfg->price * goods.mPmallcfg->buyPriceSwing / 1000, goods.mPmallcfg->price + goods.mPmallcfg->price * goods.mPmallcfg->buyPriceSwing / 1000);
	}
	if (goods.mPmallcfg->sellPrice > 0)
	{
	goods.sellPrice = Random(goods.mPmallcfg->sellPrice - goods.mPmallcfg->sellPrice * goods.mPmallcfg->sellPriceSwing / 1000, goods.mPmallcfg->sellPrice + goods.mPmallcfg->sellPrice * goods.mPmallcfg->sellPriceSwing / 1000);
	}
	goods.buyAmount = goods.mPmallcfg->buyAmount;
	//m_mapRunGoods.insert(std::make_pair(*iter, m_mapRunMallGoods[*iter]));
	m_runMallInfo.runMap.insert(std::make_pair(*iter, m_mapRunMallGoods[*iter]));
	}*/

	RUN_GOODS_MAP::iterator ibgin = _m_mapRunMallGoods.begin();
	for (; ibgin != _m_mapRunMallGoods.end(); ++ibgin)
	{
		RUN_RAND_MAP &randMap = ibgin->second;
		RUN_RAND_MAP::iterator ib = randMap.begin();
		for (; ib != randMap.end(); ++ib)
		{
			MallCfg_RandInfo &randInfo = ib->second;
			CAMP_GOODS_VEC &goodVec = randInfo.vec;
			CAMP_GOODS_VEC::iterator ibegin = goodVec.begin();
			for (; ibegin != goodVec.end(); ++ibegin)
			{
				MallGoods &goods = *ibegin;
				uint32_t randInt = Random(100);
				uint32_t randSam = goods.cRefreshWeight * 100 / randInfo.totalRand;
				if (randInt <= randSam)
				{
					if (goods.mPmallcfg->price > 0)
					{
						goods.buyPrice = Random(goods.mPmallcfg->price - goods.mPmallcfg->price * goods.mPmallcfg->buyPriceSwing / 1000, goods.mPmallcfg->price + goods.mPmallcfg->price * goods.mPmallcfg->buyPriceSwing / 1000);
					}
					if (goods.mPmallcfg->sellPrice > 0)
					{
						goods.sellPrice = Random(goods.mPmallcfg->sellPrice - goods.mPmallcfg->sellPrice * goods.mPmallcfg->sellPriceSwing / 1000, goods.mPmallcfg->sellPrice + goods.mPmallcfg->sellPrice * goods.mPmallcfg->sellPriceSwing / 1000);
					}
					goods.buyAmount = goods.mPmallcfg->buyAmount;
					m_runMallInfo.runMap.insert(std::make_pair(goods.mallid, goods));
				}
			}
		}
	}
}

void MallManager::RefreshGuildGoods(MALL_GOODS_MAP &guildmap, uint32_t level)
{
	guildmap.clear();
	for (GUILD_GOODS_MAP::iterator iter = m_mapGuildMallGoods.begin(); iter != m_mapGuildMallGoods.end(); iter++)
	{
		GUILD_RAND_MAP &map = iter->second;
		GUILD_RAND_MAP::iterator it = map.find(level);
		if (it == map.end())
			continue;
		MallCfg_RandInfo &info = it->second;
		uint32_t randint = Random(info.totalRand + 1);
		uint32_t temp = 0;
		for (CAMP_GOODS_VEC::iterator it = info.vec.begin(); it != info.vec.end(); ++it)
		{
			temp += (*it).cRefreshWeight;
			if (randint <= temp)
			{
				guildmap.insert(make_pair((*it).mallid, *it));
				break;
			}
		}
	}
}

inline void DoRun(std::set<uint32_t> &iset, std::vector<uint32_t> &iVec)
{
	uint32_t count = Random(MALL_RUN_REFRESH_MIN, MALL_RUN_REFRESH_MAX);
	uint32_t size = iVec.size();
	if (count > size)
	{
		return;
	}
	while (count > 0)
	{
		uint32_t mallId = iVec[Random(0, size - 1)];
		if (iset.count(mallId) > 0)
		{
			continue;
		}
		iset.insert(mallId);
		count--;
	}
}

void MallManager::RefreshGuildMall(uint32_t unionId, uint32_t level/*公会商铺等级*/)
{
	CUnion *pUion = g_GetUnionMgr()->GetUnion(unionId);
	if (nullptr == pUion)	return;

	SET_UINT64 members;
	pUion->AllMember(members);

	for (SET_UINT64::iterator iter = members.begin(); iter != members.end(); ++iter)
	{
		MallItem *pMallItem = FindMallItem(*iter);
		if (pMallItem == nullptr)	continue;

		pMallItem->RefreshUnionGoodsByLev(level);
	}
}

void MallManager::OnTimer(uint32_t nTimerID)
{
	switch (nTimerID)
	{
	case ETimer_ID_Load_Mall:
		{
			if (g_GetCenterService()->IsConnectDBProxy() && g_GetOfflineCharacterDataMgr()->IsFinishLoad())
			{
				LoadMallDataReq();
				g_GetTimerAxis()->KillTimer(ETimer_ID_Load_Mall, this);
			}
		}
		break;
	case ETimer_ID_Save_Mall:
		{
			if (g_GetCenterService()->IsConnectDBProxy() && g_GetOfflineCharacterDataMgr()->IsFinishLoad())
			{
				SaveDB();
			}
		}
		break;
	case ETimer_ID_Refrsh_Mall:
		{
			RefreshMall();
			RefreshCharacterTime();
		}
		break;
	case ETimer_ID_Run_Mall:
		{
			//RefreshRunGoods();
		}
		break;
	}
}

void MallManager::onClientMessage(uint32_t actionId, RECV_PACKAGE& package, uint64_t Id /* = 0 */)
{
	UNPACK_MESSAGE_CHAR_ID(package);
	switch (actionId)
	{
	case CLIENT_TO_CENTER_GET_MALL_DATA:
		{
			HandClient_AskData(charId, package);
		}
		break;
	case CLIENT_TO_CENTER_GET_TIME:
		{
			HandClient_GetTime(charId, package);
		}
		break;
	default:
		break;
	}
}

void MallManager::onServerMessage(uint32_t actionId, RECV_PACKAGE &package)
{
	switch (actionId)
	{
	case LOGIC_TO_CENTER_BUY_VERIFY_REQ:
		HandLogic_BuyVerify(package);
		break;
	case LOGIC_TO_CENTER_SELL_VERIFY:
		HandLogic_SellVerify(package);
		break;
	case  LOGIC_TO_CENTER_HANDSEL_VERIFY:
		HandLogic_HandselVerify(package);
		break;
	default:
		break;
	}
}

void MallManager::onDBProxyMessage(uint32_t actionId, RECV_PACKAGE &package)
{
	switch (actionId)
	{
	case DBPROXY_PROTOCOL_CHARACTER_MALL_DATA_RSP:
		{
			CharacterMallDBResponse rsp;
			if (!rsp.ParseFromArray(package.dataAfterHead, package.sizeAfterHead))
			{
				MMOLOG_FMT_ERROR("[center] MallManager::onDBProxyMessage CharacterMallDBResponse return but parse failed....charid:%llu,", rsp.charid());
				return;
			}
			LoadMallDataDBRet(rsp);
		}
		break;
	case DBPROXY_PROTOCOL_MALL_PLAYER_SAVE_RSP:
		{
			//TODO
		}
	break;
	default:
		break;
	}
}

void MallManager::LoadMallDataDBRet(CharacterMallDBResponse& rsp)
{
	CharIDType charId = rsp.charid();
	MallItem* pMallItem = MutMallItem(charId);
	if (nullptr != pMallItem)
	{
		pMallItem->OnLogin(rsp);
	}
	else
	{
		MMOLOG_FMT_ERROR("[center] MallManager::LoadMallDataDBRet CharacterMallDBResponse return pMallItem is nullptr charId:%llu", charId);
	}
}

void MallManager::onCharacterLogin(ActiveCharacter *pOnlineCharacter)
{
	if (nullptr == pOnlineCharacter)	return;
	CharIDType charId = pOnlineCharacter->GetCharID();
	if (g_GetCenterService()->IsConnectDBProxy())
	{
		CharacterMallDBRequest req;
		req.set_charid(charId);
		if (!g_GetCenterService()->SendDataToDBProxy(EMODULE_ID_MALL, DBPROXY_PROTOCOL_CHARACTER_MALL_DATA_REQ, &req))
		{
			MMOLOG_FMT_ERROR("[center] MallManager::onCharacterLogin SendDataToDBProxy failed...charId:%llu ", charId);
		}
		else
		{
			LogDebugFmtPrint("[center] start load character mall data....");
		}
	}
}

void MallManager::onCharacterLogout(ActiveCharacter *pOnlineCharacter)
{
	if (nullptr == pOnlineCharacter)	return;
	CharIDType charId = pOnlineCharacter->GetCharID();
	MallItemIter iter = m_mapMallItem.find(charId);
	if (iter == m_mapMallItem.end())
	{
		return;
	}
	MallItem* pMallItem = iter->second;
	if (nullptr != pMallItem)
	{
		pMallItem->SaveData(true);
		_mallItemPool->FreeObj(pMallItem);
		pMallItem = nullptr;
	}
	m_mapMallItem.erase(iter);
}

void MallManager::onCharacterDisconnect(ActiveCharacter *pOnlineCharacter)
{
	onCharacterLogout(pOnlineCharacter);
}

bool MallManager::LoadMallDataReq()
{
	GlobalDBRequst req;
	req.set_type_id(EGlobalType_Mall);

	if (!g_GetCenterService()->SendDataToDBProxy(EMODULE_ID_SERV_SYS, DBPROXY_PROTOCOL_GLOBAL_GET_REQ, &req))
	{
		LogErrFmtPrint("[center] MallManager::LoadMallDataReq...SendDataToDBProxy failed...");
	}
	return true;
}

bool MallManager::LoadMallDataRet(const string &data)
{
	if (data.length() > 0)
	{
		AllMallDBData protoMall;
		if (!protoMall.ParseFromArray(data.c_str(), (int32_t)data.length()))
		{
			MMOLOG_FMT_ERROR("[center] LoadMallDataRet parase failed...");
			return false;
		}

		uint64_t nCurTime = Time::Now().sec();
		uint64_t lastLogTm = protoMall.last_logout();
		uint64_t offTime = (lastLogTm == 0) ? 0 : (nCurTime >= lastLogTm ? nCurTime - lastLogTm : 0);
		LogDebugFmtPrint("[center] MallManager::LoadMallDataRet lastLogTm=%lu, nCurTime=%lu, offTime=%lu ....", lastLogTm, nCurTime, offTime);

		int32_t nsize = protoMall.all_mall_data_size();
		for (int32_t i = 0; i < nsize; ++i)
		{
			const MallInfo &mInfo = protoMall.all_mall_data(i);
			const MallMallCfgInfo *pMallcfg = g_GetMallMallCfgTable()->GetMallMallCfgInfo(mInfo.mall_id());
			if (nullptr == pMallcfg)
			{
				LogErrFmtPrint("[center] MallManager::LoadMallDataRet...nullptr == pMallcfg  mallid:%d ", mInfo.mall_id());
				continue;
			}

			const MallMalltypeCfgInfo *pMallTypeCfg = g_GetMallMalltypeCfgTable()->GetMallMalltypeCfgInfo(pMallcfg->mallType);
			if (nullptr == pMallTypeCfg)
			{
				LogErrFmtPrint("[center] MallManager::LoadMallDataRet...nullptr == pMallTypeCfg  mallType:%d ", pMallcfg->mallType);
				continue;
			}

			if (Mall_Sub_Type_Run == pMallTypeCfg->logicType)
			{
				DealGlobalRunDBdata(mInfo, offTime);
				continue;
			}
			DealGlobalDBdata(mInfo, offTime);
		}
	}
	else
	{
		//数据库没有记录，第一次创建需要保存
		m_bMallNeedSave = true;
	}
	m_bFinishLoad = true;

	LogDebugFmtPrint("[center] Load Mall Data finished....");

	return true;
}

bool MallManager::SaveMallDataReq(bool close)
{
	if (!close && !m_bMallNeedSave)
	{
		return true;
	}
	GlobalDBSetRequest req;
	req.set_type_id(EGlobalType_Mall);

	AllMallDBData allproto;
	for (MallGoodsIter iter = m_mapGlobalMallGoods.begin(); iter != m_mapGlobalMallGoods.end(); iter++)
	{
		MallGoods& goods = iter->second;
		MallInfo *mInfo = allproto.add_all_mall_data();
		if (nullptr != mInfo)
		{
			SetGoodsToProto(mInfo, goods);
		}
	}

	for (MallGoodsIter iter = m_runMallInfo.runMap.begin(); iter != m_runMallInfo.runMap.end(); iter++)
	{
		MallGoods& goods = iter->second;
		MallInfo *mInfo = allproto.add_all_mall_data();
		if (nullptr != mInfo)
		{
			SetGoodsToProto(mInfo, goods);
		}
	}

	if (close)
	{
		uint64_t nCurTime = Time::Now().sec();
		allproto.set_last_logout(nCurTime);
	}

	string strMall = allproto.SerializeAsString();
	req.set_data(strMall);

	if (!g_GetCenterService()->SendDataToDBProxy(EMODULE_ID_SERV_SYS, DBPROXY_PROTOCOL_GLOBAL_SAVE_REQ, &req))
	{
		LogErrFmtPrint("[center] SaveMallDataReq.....SendDataToDBProxy faild...");
		return false;
	}

	m_bMallNeedSave = false;

	return true;
}

void MallManager::SaveCharacterMallDataReq(bool close)
{
	for (MallItemIter it = m_mapMallItem.begin(); it != m_mapMallItem.end(); it++)
	{
		MallItem *mItem = it->second;
		if (nullptr == mItem)
		{
			continue;
		}
		mItem->SaveData(close);
	}
}

bool MallManager::IsFinishLoad()
{
	return m_bFinishLoad;
}

void MallManager::DealGlobalDBdata(const MallInfo &proto, uint64_t &offTime)
{
	MALL_GOODS_MAP::iterator it = m_mapGlobalMallGoods.find(proto.mall_id());
	if (it == m_mapGlobalMallGoods.end())
	{
		//TODO 走到这里说明 配置表已删除该商品
		/*MallGoods goods;
		SetProtoToGoods(proto, goods);
		InitGoods(goods);
		goods.startTick = Time::Tick();
		m_mapGlobalMallGoods.insert(make_pair(proto.mall_id(), goods));*/
	}
	else
	{
		MallGoods &goods = it->second;
		goods.mallid = proto.mall_id();
		goods.buyAmount = proto.buy_amount();
		goods.goodsAmount = proto.goods_amount();
		DealDBOffTime(proto, goods, offTime);
		goods.startTick = Time::Tick();
	}
}
void MallManager::DealGlobalRunDBdata(const MallInfo &proto, uint64_t &offTime)
{
	//MALL_GOODS_MAP::iterator it = m_mapRunGoods.find(proto.mall_id());
	MALL_GOODS_MAP::iterator it = m_runMallInfo.runMap.find(proto.mall_id());
	if (it == m_runMallInfo.runMap.end())
	{
		MallGoods goods;
		SetProtoToGoods(proto, goods);
		InitGoods(goods);
		m_runMallInfo.runMap.insert(make_pair(proto.mall_id(), goods));
	}
	else
	{
		MallGoods &goods = it->second;
		goods.mallid = proto.mall_id();
		goods.buyAmount = proto.buy_amount();
		goods.goodsAmount = proto.goods_amount();
		DealDBOffTime(proto, goods, offTime);
	}
}

void MallManager::SetProtoToGoods(const MallInfo &proto, MallGoods &goods)
{
	goods.mallid = proto.mall_id();
	goods.buyAmount = proto.buy_amount();
	goods.goodsAmount = proto.goods_amount();
	goods.goodsTime = proto.goods_time();
	goods.buyTime = proto.buy_time();
	goods.openTime = proto.open_time();
	goods.openCoolTime = proto.open_cool_time();
	goods.buyPrice = proto.buy_price();
	goods.sellPrice = proto.sell_price();
}

void MallManager::SetGoodsToProto(MallInfo *proto, MallGoods &goods)
{
	proto->set_mall_id(goods.mallid);
	proto->set_buy_amount(goods.buyAmount);
	proto->set_goods_amount(goods.goodsAmount);
	proto->set_goods_time(goods.goodsTime);
	proto->set_buy_time(goods.buyTime);
	proto->set_open_time(goods.openTime);
	proto->set_open_cool_time(goods.openCoolTime);
	proto->set_buy_price(goods.buyPrice);
	proto->set_sell_price(goods.sellPrice);
}

void MallManager::DealDBOffTime(const MallInfo &proto, MallGoods &goods, uint64_t &offTime)
{
	//限销类要减去停服时间
	if (goods.cGoodsTime > 0)
	{
		//goods.goodsTime = proto.goods_time() > offTime ? proto.goods_time() - offTime : goods.cGoodsTime;
		//goods.goodsTime = goods.goodsTime > goods.cGoodsTime ? goods.cGoodsTime : goods.goodsTime;
		if (proto.goods_time() > offTime)
		{
			goods.goodsTime = proto.goods_time() - offTime;
		}
		else
		{
			goods.goodsTime = goods.cGoodsTime;
		}
		if (goods.goodsTime == goods.cGoodsTime || goods.goodsTime <= MALL_PRE_REFRESH_SEC)
		{
			goods.goodsTime = goods.cGoodsTime;
			goods.goodsAmount = goods.cGoodsAmount;
		}
		goods.startTick_s = goods.goodsTime;
	}
	//限购类要减去玩家离线时间
	if (goods.cBuyTime > 0)
	{
		//goods.buyTime = proto.buy_time() > offTime ? proto.buy_time() - offTime : goods.cBuyTime;
		//goods.buyTime = goods.buyTime > goods.cBuyTime ? goods.cBuyTime : goods.buyTime;
		if (proto.buy_time() > offTime)
		{
			goods.buyTime = proto.buy_time() - offTime;
		}
		else
		{
			goods.buyTime = goods.cBuyTime;
			goods.buyAmount = goods.cBuyAmount;
		}
		if (goods.buyTime <= MALL_PRE_REFRESH_SEC)
		{
			goods.buyTime = goods.cBuyTime;
			goods.buyAmount = goods.cBuyAmount;
		}
		goods.startTick_s = goods.buyTime;
	}
	//处理开放时间
	if (goods.cOpenTime <= 0)	return;
	
	goods.openTime = proto.open_time();
	goods.openCoolTime = proto.open_cool_time();
	if (goods.openTime == 0)
	{
		goods.openTime = (goods.openCoolTime > offTime) ? goods.openTime : goods.cOpenTime;
		goods.openCoolTime = (goods.openCoolTime > offTime) ? (goods.openCoolTime - offTime) : 0;
		if (goods.openCoolTime <= MALL_PRE_REFRESH_SEC)
		{
			goods.openTime = goods.cOpenTime;
			goods.openCoolTime = 0;
			goods.startTick_s = goods.openTime;
		}
		else
		{
			goods.startTick_s = goods.openCoolTime;
		}

	}
	else
	{
		goods.openCoolTime = (goods.openTime > offTime) ? goods.openCoolTime : goods.cOpenCoolTime;
		goods.openTime = (goods.openTime > offTime) ? (goods.openTime - offTime) : 0;
		if (goods.openTime <= MALL_PRE_REFRESH_SEC)
		{
			goods.openCoolTime = goods.cOpenCoolTime;
			goods.openTime = 0;
			goods.startTick_s = goods.openCoolTime;
		}
		else
		{
			goods.startTick_s = goods.openTime;
		}
	}
}

void MallManager::HandClient_AskData(CharIDType charId, RECV_PACKAGE &package)
{
	Mall_AskData askReq;
	if (!askReq.ParseFromArray(package.dataAfterHead, package.sizeAfterHead))
	{
		MMOLOG_FMT_ERROR("[center] MallManager::HandClient_AskData askReq parse failed...");
		return;
	}

	Mall_AskDataRsp askMallDataRsp;
	askMallDataRsp.set_mall_type(askReq.mall_type());

	OfflineCharacterData *pOffline = g_GetOfflineCharacterDataMgr()->GetOfflineCharacter(charId);
	if (nullptr == pOffline)
	{
		g_GetCenterService()->SendDataToClient(charId, EMODULE_ID_MALL, CENTER_TO_CLIENT_ASK_DATA_RESULT, &askMallDataRsp);
		return;
	}
	
	if (askReq.mall_type() <= 0)
	{
		AskData(pOffline);
		return;
	}

	const MallMalltypeCfgInfo *pMallTypeCfg = g_GetMallMalltypeCfgTable()->GetMallMalltypeCfgInfo(askReq.mall_type());
	if (nullptr == pMallTypeCfg)
	{
		MMOLOG_FMT_ERROR("[center] MallManager::HandClient_AskData pMallTypeCfg=nullptr.......failed...");
		g_GetCenterService()->SendDataToClient(charId, EMODULE_ID_MALL, CENTER_TO_CLIENT_ASK_DATA_RESULT, &askMallDataRsp);
		return;
	}

	if (Mall_Group_Type_Main == pMallTypeCfg->groupType)
	{
		for (MallGoodsIter it = m_mapGlobalMallGoods.begin(); it != m_mapGlobalMallGoods.end(); it++)
		{
			MallGoods &goods = it->second;
			//还在上架冷却时间
			//if (goods.cOpenTime > 0 && goods.openCoolTime > 0)				continue;
			if (goods.mPmallcfg->mallType != (int32_t)askReq.mall_type())	continue;
			MallProtoInfo *mInfo = askMallDataRsp.add_data();
			if (nullptr == mInfo)	continue;
			mInfo->set_mall_id(goods.mallid);
			mInfo->set_amount(goods.goodsAmount);
			if (goods.cOpenTime > 0)
				mInfo->set_is_close(goods.openTime > 0 ? 0 : 1);
		}
	}

	if (pMallTypeCfg->logicType == Mall_Sub_Type_Run)
	{
		for (MallGoodsIter it = m_runMallInfo.runMap.begin(); it != m_runMallInfo.runMap.end(); it++)
		{
			MallGoods &goods = it->second;
			if (goods.mPmallcfg->mallType != (int32_t)askReq.mall_type())	continue;
			MallProtoInfo *mInfo = askMallDataRsp.add_data();
			if (nullptr == mInfo)											continue;
			//LogInfoFmtPrint("[logic]askdata+++++++++++++++++++++++mallId:%d,goodsAmount:%d,buyPrice:%d,sellPrice:%d", goods.mallid, goods.goodsAmount, goods.buyPrice, goods.sellPrice);
			mInfo->set_mall_id(goods.mallid);
			mInfo->set_amount(goods.goodsAmount);
			mInfo->set_buy_price(goods.buyPrice);
			mInfo->set_sell_price(goods.sellPrice);
		}
	}

	MallItem* pMallItem = FindMallItem(charId);
	if (nullptr != pMallItem)
	{
		//整合全局和玩家数据
		pMallItem->Merge(pOffline, askMallDataRsp, pMallTypeCfg);
	}

	//LogDebugFmtPrint("[center] MallManager::HandClient_AskData...player mall goods size = %u ", askMallDataRsp.data_size());
	g_GetCenterService()->SendDataToClient(charId, EMODULE_ID_MALL, CENTER_TO_CLIENT_ASK_DATA_RESULT, &askMallDataRsp);
};
void MallManager::AskData(OfflineCharacterData *pOffline)
{
	Mall_AskDataRsp rsp;
	if (nullptr == pOffline)
	{
		g_GetCenterService()->SendDataToClient(pOffline->GetCharID(), EMODULE_ID_MALL, CENTER_TO_CLIENT_ASK_DATA_RESULT, &rsp);
		return;
	}

	for (MallGoodsIter it = m_mapGlobalMallGoods.begin(); it != m_mapGlobalMallGoods.end(); it++)
	{
		MallGoods &goods = it->second;
		//还在上架冷却时间
		//if (goods.cOpenTime > 0 && goods.openCoolTime > 0)				continue;
		MallProtoInfo *mInfo = rsp.add_data();
		if (nullptr == mInfo)	continue;
		mInfo->set_mall_id(goods.mallid);
		mInfo->set_amount(goods.goodsAmount);
		if (goods.cOpenTime > 0)
			mInfo->set_is_close(goods.openTime > 0 ? 0 : 1);
	}
	
	for (MallGoodsIter it = m_runMallInfo.runMap.begin(); it != m_runMallInfo.runMap.end(); it++)
	{
		MallGoods &goods = it->second;
		MallProtoInfo *mInfo = rsp.add_data();
		if (nullptr == mInfo)											continue;
		mInfo->set_mall_id(goods.mallid);
		mInfo->set_amount(goods.goodsAmount);
		mInfo->set_buy_price(goods.buyPrice);
		mInfo->set_sell_price(goods.sellPrice);
	}

	MallItem* pMallItem = FindMallItem(pOffline->GetCharID());
	if (nullptr != pMallItem)
	{
		//整合全局和玩家数据
		pMallItem->Merge(pOffline, rsp);
	}

	g_GetCenterService()->SendDataToClient(pOffline->GetCharID(), EMODULE_ID_MALL, CENTER_TO_CLIENT_ASK_DATA_RESULT, &rsp);
}

void MallManager::HandClient_GetTime(CharIDType charId, RECV_PACKAGE &package)
{
	ActiveCharacter *pOnline = g_GetActiveCharacterMgr()->GetOnlineCharacter(charId);
	if (nullptr == pOnline)
	{
		LogErrFmtPrint("MallManager::HandClient_GetTime....nullptr == pOnline , charid:%lu ", charId);
		return;
	}

	Mall_GetTimeReq getTimeReq;
	Mall_GetTimeRsp getTimeRsp;
	if (!getTimeReq.ParseFromArray(package.dataAfterHead, package.sizeAfterHead))
	{
		MMOLOG_FMT_ERROR("[center] MallManager::HandClient_GetTime getTimeReq parse failed...");
		return;
	}

	const MallMallCfgInfo *pMallcfg = g_GetMallMallCfgTable()->GetMallMallCfgInfo(getTimeReq.mall_id());
	if (nullptr == pMallcfg)
	{
		LogErrFmtPrint("[center] MallManager::HandClient_GetTime...nullptr == pMallcfg  mall_id:%u ", getTimeReq.mall_id());
		return;
	}

	const MallMalltypeCfgInfo *pMallTypeCfg = g_GetMallMalltypeCfgTable()->GetMallMalltypeCfgInfo(pMallcfg->mallType);
	if (nullptr == pMallTypeCfg)
	{
		LogErrFmtPrint("[center] MallManager::HandClient_GetTime pMallTypeCfg=nullptr.......failed...");
		return;
	}

	MallItem *mItem = MutMallItem(charId);
	if (nullptr == mItem)
	{
		LogErrFmtPrint("[center] MallManager::HandClient_GetTime...nullptr == mItem  charId:%lu ", charId);
		return;
	}

	getTimeRsp.set_mall_id(getTimeReq.mall_id());
	uint64_t cTime = 0;
	uint64_t cOpenTime = 0;
	uint32_t count = 0;

	if (Mall_Group_Type_Main == pMallTypeCfg->groupType)
	{
		MallGoodsIter it = m_mapGlobalMallGoods.find(getTimeReq.mall_id());
		if (it != m_mapGlobalMallGoods.end())
		{
			MallGoods &goods = it->second;
			cTime = goods.goodsTime;
			cOpenTime = goods.openTime;
			count = goods.goodsAmount;
		}
	}

	if (Mall_Sub_Type_Run == pMallTypeCfg->logicType)
	{
		MallGoodsIter it = m_runMallInfo.runMap.find(getTimeReq.mall_id());
		if (it != m_runMallInfo.runMap.end())
		{
			MallGoods &goods = it->second;
			count = pMallcfg->goodsAmount > 0 ? goods.goodsAmount : 0;
		}
		cTime = m_runMallInfo.left_fresh_time;
	}

	mItem->GetTime(getTimeReq.mall_id(), pMallTypeCfg, cTime, cOpenTime, count);

	getTimeRsp.set_time(cTime);
	getTimeRsp.set_open_time(cOpenTime);
	getTimeRsp.set_count(count);
	g_GetCenterService()->SendDataToClient(charId, EMODULE_ID_MALL, CENTER_TO_CLIENT_GET_TIME_RESULT, &getTimeRsp);
}

void MallManager::HandLogic_BuyVerify(RECV_PACKAGE &package)
{
	Mall_Buy_VerifyReq verifyReq;
	Mall_Buy_VerifyRsp verifyRsp;
	if (!verifyReq.ParseFromArray(package.dataAfterHead, package.sizeAfterHead))
	{
		MMOLOG_FMT_ERROR("[center] MallManager::HandLogic_BuyVerify verifyReq parse failed...");
		return;
	}
	CharIDType charId = verifyReq.char_id();
	verifyRsp.set_char_id(charId);
	verifyRsp.set_result(RET_FAIL);
	verifyRsp.set_count(verifyReq.count());
	verifyRsp.set_mall_id(verifyReq.mall_id());

	const MallMallCfgInfo *pMallcfg = g_GetMallMallCfgTable()->GetMallMallCfgInfo(verifyReq.mall_id());
	if (nullptr == pMallcfg)
	{
		LogErrFmtPrint("[center] MallManager::HandLogic_BuyVerify...nullptr == pMallcfg  mall_id:%u ", verifyReq.mall_id());
		verifyRsp.set_result(RET_CONFIG_ERROR);
		g_GetCenterService()->SendDataToLogicByCharID(charId, EMODULE_ID_MALL, CENTER_TO_LOGIC_BUY_VERIFY_RSP, &verifyRsp);
		return;
	}

	const MallMalltypeCfgInfo *pMallTypeCfg = g_GetMallMalltypeCfgTable()->GetMallMalltypeCfgInfo(pMallcfg->mallType);
	if (nullptr == pMallTypeCfg)
	{
		LogErrFmtPrint("[center] MallManager::HandLogic_BuyVerify...nullptr == pMallTypeCfg  mall_id:%u ", pMallcfg->mallType);
		verifyRsp.set_result(RET_CONFIG_ERROR);
		g_GetCenterService()->SendDataToLogicByCharID(charId, EMODULE_ID_MALL, CENTER_TO_LOGIC_BUY_VERIFY_RSP, &verifyRsp);
		return;
	}

	//普通商品 不限购买
	if (pMallcfg->goodsAmount == 0 && pMallcfg->buyAmount == 0)
	{
		verifyRsp.set_result(RET_SUCCESS);
	}
	
	if (pMallTypeCfg->logicType == Mall_Sub_Type_Camp)
	{
		//军功商城
		ERetCode retCode = Verify_Camp(charId, verifyReq, pMallcfg);
		verifyRsp.set_result(retCode);
	}
	else if (pMallTypeCfg->logicType == Mall_Sub_Type_Arena)
	{
		//竞技场商城
		ERetCode retCode = Verify_Arena(charId, verifyReq, pMallcfg);
		verifyRsp.set_result(retCode);
	}
	else if (pMallTypeCfg->logicType == Mall_Sub_Type_Guild)
	{
		//公会商城
		ERetCode retCode = Verify_Guild(charId, verifyReq, pMallcfg);
		verifyRsp.set_result(retCode);
	}
	else if (pMallTypeCfg->logicType == Mall_Sub_Type_Run)
	{
		//跑商商城
		uint32_t needFund = 0;
		ERetCode retCode = Verify_Run(charId, verifyReq, needFund);
		verifyRsp.set_result(retCode);
		verifyRsp.set_fund(needFund);
	}
	else if (pMallTypeCfg->logicType == Mall_Sub_Type_LostCity)
	{
		//遗失之城商铺购买
		uint32_t unionId = g_GetUnionMgr()->GetCharUnionId(charId);
		uint32_t winUnionId = g_GetUnionMgr()->GetWinUnionId();
		LostCityCharInfo *pCharInfo = g_GetUnionMgr()->FindCityScore(charId);
		if (unionId <= 0)
			verifyRsp.set_result(RET_UNION_NOT_JOIN);
		else if (nullptr == pCharInfo)
			verifyRsp.set_result(RET_ACTIVITY_LOST_CITY_REWAED_ERROR);
		//else if (0 == winUnionId)
		//	verifyRsp.set_result(RET_MALL_LOST_CITY_FAIL);	没有分出胜负
		else if (unionId != winUnionId)
			verifyRsp.set_result(RET_MALL_LOST_CITY_FAIL);
		else if (pCharInfo->buyTimes >= ACTIVITY_LOST_CITY_MALL_BUY_TIMES_LIMIT)
			verifyRsp.set_result(RET_MALL_FUNDBUS_BUY_TIMES_LIMIT);
		else
		{
			verifyRsp.set_result(RET_SUCCESS);
			pCharInfo->buyTimes++;
		}
	}
	else if (pMallcfg->openTime > 0)
	{
		//限时上下架
		MallGoodsIter it = m_mapGlobalMallGoods.find(verifyReq.mall_id());
		if (it != m_mapGlobalMallGoods.end())
		{
			MallGoods &goods = it->second;
			if (goods.openTime > 0)
				verifyRsp.set_result(RET_SUCCESS);
			else
				verifyRsp.set_result(RET_MALL_GOODS_COUNT_LACK);
		}
	}
	else if (pMallcfg->goodsAmount > 0)
	{
		//限销商品
		MallGoodsIter it = m_mapGlobalMallGoods.find(verifyReq.mall_id());
		if (it != m_mapGlobalMallGoods.end())
		{
			MallGoods &goods = it->second;
			if (goods.goodsAmount >= verifyReq.count())
			{
				verifyRsp.set_result(RET_SUCCESS);
				goods.goodsAmount -= verifyReq.count();
				ChangeNotify(goods, Mall_Operate_type_Change, charId);
				m_bMallNeedSave = true;
			}
			else
			{
				verifyRsp.set_result(RET_MALL_GOODS_COUNT_LACK);
			}
		}
	}
	else if (pMallcfg->buyAmount > 0)
	{
		//限购商品
		MallItem *mItem = MutMallItem(charId);
		if (mItem != nullptr)
		{
			ERetCode retCode = mItem->Verify(verifyReq.mall_id(), verifyReq.count());
			verifyRsp.set_result(retCode);
		}
	}

	g_GetCenterService()->SendDataToLogicByCharID(charId, EMODULE_ID_MALL, CENTER_TO_LOGIC_BUY_VERIFY_RSP, &verifyRsp);
}

void MallManager::HandLogic_SellVerify(RECV_PACKAGE &package)
{
	Mall_Sell_VerifyReq verifyReq;
	Mall_Sell_VerifyRsp verifyRsp;
	if (!verifyReq.ParseFromArray(package.dataAfterHead, package.sizeAfterHead))
	{
		MMOLOG_FMT_ERROR("[center] MallManager::HandLogic_SellVerify Mall_Sell_VerifyReq parse failed...");
		return;
	}

	uint32_t sellFund = 0;
	ERetCode retCode = RET_FAIL;
	MallGoodsIter it = m_runMallInfo.runMap.find(verifyReq.mall_id());
	if (it != m_runMallInfo.runMap.end())
	{
		MallGoods &goods = it->second;
		if (goods.sellPrice > 0)
		{
			sellFund = goods.sellPrice * verifyReq.count();
			retCode = RET_SUCCESS;

			/*uint32_t cur_fund = verifyReq.money();
			uint32_t goal_fund = verifyReq.g_money();
			if ((cur_fund + (verifyReq.count() - 1) * goods.sellPrice) >= goal_fund)
			{
				retCode = RET_MALL_RUN_FUND_COUNT_OVER;
			}
			else
			{
				sellFund = goods.sellPrice * verifyReq.count();
				retCode = RET_SUCCESS;
			}*/
		}
	}

	verifyRsp.set_char_id(verifyReq.char_id());
	verifyRsp.set_result(retCode);
	verifyRsp.set_item_idx(verifyReq.item_idx());
	verifyRsp.set_mall_id(verifyReq.mall_id());
	verifyRsp.set_count(verifyReq.count());
	verifyRsp.set_money(sellFund);
	g_GetCenterService()->SendDataToLogicByCharID(verifyReq.char_id(), EMODULE_ID_MALL, CENTER_TO_LOGIC_SELL_VERIFY, &verifyRsp);
}

void MallManager::HandLogic_HandselVerify(RECV_PACKAGE &package)
{
	Mall_Handsel_VerifyReq verifyReq;
	Mall_Handsel_VerifyRsp verifyRsp;
	if (!verifyReq.ParseFromArray(package.dataAfterHead, package.sizeAfterHead))
	{
		MMOLOG_FMT_ERROR("[center] MallManager::HandLogic_HandselVerify Mall_Handsel_VerifyReq parse failed...");
		return;
	}

	OfflineCharacterData *pFromOffline = g_GetOfflineCharacterDataMgr()->GetOfflineCharacter(verifyReq.char_id());
	if (nullptr == pFromOffline)
	{
		Mall_HandselRsp rsp;
		rsp.set_retcode(RET_NOT_HAVE_CHARACTER);
		g_GetCenterService()->SendDataToClient(verifyReq.char_id(), EMODULE_ID_MALL, LOGIC_TO_CLIENT_HANDSEL, &rsp);
		return;
	}

	OfflineCharacterData *pOffline = g_GetOfflineCharacterDataMgr()->GetOfflineCharacter(verifyReq.target_id());
	if (nullptr == pOffline)
	{
		Mall_HandselRsp rsp;
		rsp.set_retcode(RET_NOT_HAVE_CHARACTER);
		g_GetCenterService()->SendDataToClient(verifyReq.char_id(), EMODULE_ID_MALL, LOGIC_TO_CLIENT_HANDSEL, &rsp);
		return;
	}

	const MallMallCfgInfo *pMallcfg = g_GetMallMallCfgTable()->GetMallMallCfgInfo(verifyReq.mall_id());
	if (nullptr == pMallcfg)
	{
		LogErrFmtPrint("[center] MallManager::HandLogic_HandselVerify...nullptr == pMallcfg  mall_id:%u ", verifyReq.mall_id());
		Mall_HandselRsp rsp;
		rsp.set_retcode(RET_CONFIG_ERROR);
		g_GetCenterService()->SendDataToClient(verifyReq.char_id(), EMODULE_ID_MALL, LOGIC_TO_CLIENT_HANDSEL, &rsp);
		return;
	}

	//TODO 扣除商品(限销限购)

	//发送邮件
	string mailTitle = "商城赠送";
	LIST_ITEM items;
	items.clear();
	SItem itemInfo;
	itemInfo.nItemID = pMallcfg->itemID;
	itemInfo.nNum = verifyReq.count();
	items.push_back(itemInfo);
	if (!g_GetMailMgr()->SendP2PMail(verifyReq.target_id(), verifyReq.char_id(), pFromOffline->GetCharName(), mailTitle, verifyReq.msg(), items, 0, 0, 0, 0, 0))
	{
		Mall_HandselRsp rsp;
		rsp.set_retcode(RET_FAIL);
		g_GetCenterService()->SendDataToClient(verifyReq.char_id(), EMODULE_ID_MALL, LOGIC_TO_CLIENT_HANDSEL, &rsp);
		return;
	}
	
	verifyRsp.set_result(RET_SUCCESS);
	verifyRsp.set_char_id(verifyReq.char_id());
	verifyRsp.set_mall_id(verifyReq.mall_id());
	verifyRsp.set_count(verifyReq.count());
	g_GetCenterService()->SendDataToLogicByCharID(verifyReq.char_id(), EMODULE_ID_MALL, CENTER_TO_LOGIC_HANDSEL_VERIFY, &verifyRsp);
}

void MallManager::Cost_Camp(CharIDType charId, const MallMallCfgInfo *pMallcfg, uint32_t count)
{
	OfflineCharacterData *pOffline = g_GetOfflineCharacterDataMgr()->GetOfflineCharacter(charId);
	if (nullptr == pOffline)
	{
		LogErrFmtPrint("[center] MallManager::Cost...pOffline==nullptr  charId:%lu ", charId);
		return;
	}
	ActiveCharacter *pOnline = g_GetActiveCharacterMgr()->GetOnlineCharacter(pOffline->GetCharID());
	if (nullptr == pOnline)
	{
		LogErrFmtPrint("[center] MallManager::Cost...pOnline==nullptr  charId:%lu ", charId);
		return;
	}

	uint32_t needContri = (pMallcfg->discount == 0) ? (pMallcfg->price * count) : (pMallcfg->price * pMallcfg->discount / 100 * count);
	uint32_t curContri = pOffline->GetContriCoin();
	if (curContri < needContri)
	{
		LogErrFmtPrint("[center] MallManager::Cost...player ContriCoin < needContriCoin  charId:%lu ", charId);
		return;
	}

	pOffline->SetContriCoin(curContri - needContri);
	CenterToLogic_CampCharInfo notify;
	notify.set_charid(charId);
	notify.add_attr_id(C_CAMP_COIN);
	notify.add_attr_value(pOffline->GetContriCoin());
	if (!g_GetCenterService()->SendDataToLogicByCharID(charId, EMODULE_ID_CAMP, CENTER_TO_LOGIC_CAMP_CHAR_INFO_NOTIFY, &notify))
	{
		LogErrFmtPrint("[center] MallManager::Cost...SendDataToLogicByCharID failed.. byCampID:%d,charid:%u ", pOffline->GetCampID(), pOffline->GetCharID());
	}
}

void MallManager::DailyUpdate()
{
	for (MallItemIter it = m_mapMallItem.begin(); it != m_mapMallItem.end(); it++)
	{
		MallItem *mItem = it->second;
		if (nullptr == mItem)
		{
			continue;
		}
		mItem->RefreshCampGoods(true);
		mItem->RefreshArenaGoods(true);
		mItem->RefreshUnionGoods(true);
	}
}

void MallManager::SetByOperate(Mall_Operate_SetType type, uint32_t value)
{
	CenterToLogicOperateSet operateSet;
	operateSet.set_operate_type(type);
	operateSet.set_value(value);
	g_GetCenterService()->SendDataToAllLogic(EMODULE_ID_ACTIVITY, CENTER_TO_LOGIC_OPERATE_SET, &operateSet);
}

MallItem* MallManager::FindMallItem(CharIDType charID)
{
	MallItemIter iter = m_mapMallItem.find(charID);
	if (iter == m_mapMallItem.end())
	{
		return nullptr;
	}
	return iter->second;
}

MallItem* MallManager::MutMallItem(CharIDType charID)
{
	MallItemIter iter = m_mapMallItem.find(charID);
	if (iter != m_mapMallItem.end())
	{
		return iter->second;
	}
	
	MallItem* pMallItem = _mallItemPool->MallocObj();
	if (nullptr == pMallItem)
	{
		LogErrFmtPrint("[center] MallManager::MutMallItem MallItem MallocObj faild charId:%lu", charID);
		return nullptr;
	}

	pMallItem->Init(charID);
	m_mapMallItem[charID] = pMallItem;
	return pMallItem;
}

void MallManager::RefreshMall()
{
	uint64_t tick = Time::Tick();
	for (MallGoodsIter it = m_mapGlobalMallGoods.begin(); it != m_mapGlobalMallGoods.end(); it++)
	{
		MallGoods &goods = it->second;
		if (goods.cGoodsTime > 0)
			GoMallTime(goods, tick);
		if (goods.cOpenTime > 0)
			GoOpenTime(goods, tick);
	}
	GoRunTime(tick);
}

void MallManager::GoMallTime(MallGoods &goods, const uint64_t &tick)
{
	if (tick < goods.startTick)
	{
		goods.startTick = tick;
		return;
	}
	uint32_t diffSec = ((uint32_t)(tick - goods.startTick)) / 1000;		//刷新时间
	if (diffSec > goods.startTick_s)
	{
		goods.goodsAmount = goods.cGoodsAmount;
		goods.goodsTime = goods.cGoodsTime;
		goods.startTick = tick;
		goods.startTick_s = goods.mPmallcfg->goodsRefreshTime;
		return;
	}
	if (goods.goodsTime == MALL_PRE_REFRESH_SEC)
	{
		goods.goodsAmount = goods.cGoodsAmount;
	}
	if (goods.goodsTime == 0)
	{
		goods.goodsTime = goods.cGoodsTime;
		goods.startTick = Time::Tick();
		goods.startTick_s = goods.goodsTime;
		return;
	}
	goods.goodsTime = goods.startTick_s - diffSec;
	//LogDebugFmtPrint("+++++++++++++++++++goodtime++++++++++++++++%lu", goods.goodsTime);
}

void MallManager::GoOpenTime(MallGoods &goods, const uint64_t &tick)
{
	if (tick < goods.startTick)
	{
		goods.startTick = tick;
		return;
	}
	
	uint32_t diffSec = ((uint32_t)(tick - goods.startTick)) / 1000;		//刷新时间
	if (goods.openTime == 0)
	{
		if ((goods.openCoolTime == MALL_PRE_REFRESH_SEC) || (diffSec > goods.startTick_s))
		{
			goods.openCoolTime = 0;
			goods.openTime = goods.cOpenTime;
			goods.startTick = tick;
			goods.startTick_s = goods.openTime;
			return;
		}
		goods.openCoolTime = goods.startTick_s - diffSec;
	}
	else
	{
		if ((goods.openTime == MALL_PRE_REFRESH_SEC) || (diffSec > goods.startTick_s))
		{
			goods.openTime = 0;
			goods.openCoolTime = goods.cOpenCoolTime;
			goods.startTick = tick;
			goods.startTick_s = goods.openCoolTime;
			return;
		}
		goods.openTime = goods.startTick_s - diffSec;
	}
	//LogDebugFmtPrint("+++++++++++++++++opentime++++++++++++++++++%lu,%lu", goods.openTime, goods.openCoolTime);
}

void MallManager::GoRunTime(const uint64_t &tick)
{
	if (m_runMallInfo.start_tick <= 0)
	{
		m_runMallInfo.start_tick = tick;
		return;
	}
	if (tick < m_runMallInfo.start_tick)
	{
		m_runMallInfo.start_tick = tick;
		return;
	}
	uint32_t diffSec = ((uint32_t)(tick - m_runMallInfo.start_tick)) / 1000;		//刷新时间
	//LogDebugFmtPrint("+++++++++++++++++run++++++++++++++++++diffSec:%d", diffSec);
	if (diffSec == (MALL_RUN_REFRESH_SEC - MALL_PRE_REFRESH_SEC))	//服务端提前两秒刷
	{
		RefreshRunGoods();
	}
	if (diffSec == MALL_RUN_REFRESH_SEC)
	{
		m_runMallInfo.start_tick = tick;
	}
	if (diffSec > MALL_RUN_REFRESH_SEC)
	{
		m_runMallInfo.start_tick = tick;
	}
	else
		m_runMallInfo.left_fresh_time = MALL_RUN_REFRESH_SEC - diffSec;

	//m_runMallInfo.left_fresh_time = MALL_RUN_REFRESH_SEC - diffSec;
	//m_runMallInfo.left_fresh_time = (MALL_RUN_REFRESH_SEC >= diffSec) ? MALL_RUN_REFRESH_SEC - diffSec : MALL_RUN_REFRESH_SEC;
	//LogDebugFmtPrint("+++++++++++++++++run++++++++++++++++++%lu", m_runMallInfo.left_fresh_time);
}

void MallManager::RefreshCharacterTime()
{
	uint64_t tick = Time::Tick();
	for (MallItemIter it = m_mapMallItem.begin(); it != m_mapMallItem.end(); it++)
	{
		MallItem *mItem = it->second;
		if (nullptr == mItem)
		{
			continue;
		}
		mItem->Refresh(tick);
	}
}

void MallManager::ChangeNotify(MallGoods &goods, Mall_Operate_type type, CharIDType charId)
{
	Mall_Chang_Notify notify;
	notify.set_operate_type(type);
	notify.set_char_id(charId);
	notify.set_mall_id(goods.mallid);
	notify.set_count(goods.goodsAmount);
	notify.set_time(goods.goodsTime);
	notify.set_open_time(goods.openTime);
	g_GetCenterService()->SendDataToClient(charId, EMODULE_ID_MALL, CENTER_TO_CLIENT_CHANGE_NOTIFY, &notify);
}

ERetCode MallManager::Verify_Camp(CharIDType charId, Mall_Buy_VerifyReq &buyreq, const MallMallCfgInfo *cfg)
{
	MallItem *mItem = MutMallItem(charId);
	if (mItem == nullptr)
	{
		LogErrFmtPrint("[center] MallManager::Verify_Camp...MallItem==nullptr....mallId:%u ", buyreq.mall_id());
		return RET_FAIL;
	}
	
	ERetCode retCode = mItem->Verify_Camp(buyreq.mall_id(), buyreq.count());
	if (retCode == RET_SUCCESS)
	{
		Cost_Camp(charId, cfg, buyreq.count());
		return RET_SUCCESS;
	}
	return retCode;
}

ERetCode MallManager::Verify_Guild(CharIDType charId, Mall_Buy_VerifyReq &buyreq, const MallMallCfgInfo *cfg)
{
	OfflineCharacterData *pOffline = g_GetOfflineCharacterDataMgr()->GetOfflineCharacter(charId);
	if (nullptr == pOffline)
	{
		LogErrFmtPrint("[center] MallManager::Verify_Guild...pOffline==nullptr  charId:%lu ", charId);
		return RET_FAIL;
	}

	CUnion *pUnion = g_GetUnionMgr()->GetCharUnion(charId);
	if (nullptr == pUnion)
	{
		return RET_UNION_NOT_JOIN;
	}

	if (pUnion->FuncLimit())
	{
		return RET_UNION_FUN_LIMIT;
	}

	if (pUnion->WarnLine())
	{
		return RET_UNION_MONEY_IN_WARN_LINE;
	}

	MallItem *mItem = MutMallItem(charId);
	if (mItem == nullptr)
	{
		LogErrFmtPrint("[center] MallManager::Verify_Guild...MallItem==nullptr....mallId:%u ", buyreq.mall_id());
		return RET_FAIL;
	}

	int64_t cost = (cfg->discount == 0) ? (cfg->price * buyreq.count()) : (cfg->price * cfg->discount / 100 * buyreq.count());
	if (pOffline->GetUnionUseContri() < cost)
	{
		return RET_MALL_UNIONCONTRI_LACK;
	}

	ERetCode retCode = mItem->Verify_Union(buyreq.mall_id(), buyreq.count());
	if (retCode != RET_SUCCESS)
	{
		return retCode;
	}

	g_GetUnionMgr()->AddCharCanUseContri(charId, -cost, S_UNION_MALL);

	return RET_SUCCESS;
}

ERetCode MallManager::Verify_Arena(CharIDType charId, Mall_Buy_VerifyReq &buyreq, const MallMallCfgInfo *cfg)
{
	MallItem *mItem = MutMallItem(charId);
	if (mItem == nullptr)
	{
		LogErrFmtPrint("[center] MallManager::Verify_Arena...MallItem==nullptr....mallId:%u ", buyreq.mall_id());
		return RET_FAIL;
	}

	return mItem->Verify_Arena(buyreq.mall_id(), buyreq.count());
}

ERetCode MallManager::Verify_Run(CharIDType charId, Mall_Buy_VerifyReq &buyreq, /*const MallMallCfgInfo *cfg, */uint32_t &needFund)
{
/*
	MallItem *mItem = MutMallItem(charId);
	if (mItem == nullptr)
	{
		LogErrFmtPrint("[center] MallManager::Verify_Run...MallItem==nullptr....mallId:%u ", buyreq.mall_id());
		return RET_FAIL;
	}

	return mItem->Verify_Run(buyreq.mall_id(), buyreq.count(), buyreq.fund(), needFund);*/


	ERetCode retCode = RET_FAIL;
	MallGoodsIter it = m_runMallInfo.runMap.find(buyreq.mall_id());
	if (it == m_runMallInfo.runMap.end())
	{
		//return RET_MALL_GOODS_NOT_EXIST;
		it = m_runMallInfo.preRunMap.find(buyreq.mall_id());
		if (it == m_runMallInfo.preRunMap.end())
		{
			return RET_MALL_GOODS_NOT_EXIST;
		}
	}
	
	MallGoods &goods = it->second;
	uint32_t need_fund = goods.buyPrice * buyreq.count();
	if (goods.goodsAmount < buyreq.count())
	{
		retCode = RET_MALL_BUY_COUNT_LIMIT;
	}
	else if (buyreq.fund() < need_fund)
	{
		retCode = RET_MALL_RUN_FUND_LACK;
	}
	else
	{
		needFund = need_fund;
		goods.goodsAmount -= buyreq.count();
		retCode = RET_SUCCESS;
		ChangeNotify(goods, Mall_Operate_type_Change, charId);
	}
	
	return retCode;
}
